package edu.neu.cs6515.gui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.event.*;

import javax.swing.JComponent;

import lombok.Getter;
import lombok.Setter;
import edu.neu.cs6515.xml.IngeniousColor;

/**
 * class to render a hexagon cell
 */
public class CellRenderer extends JComponent {

    private static final long serialVersionUID = 1L;
    public static final int RADIUS = 18;
    public static final int DIAMETER = RADIUS * 2;
    public static final double SIDES = 6;

    @Getter
    private int distance;

    @Getter
    private int angle;

    @Setter
    @Getter
    private IngeniousColor ingeniousColor = IngeniousColor.WHITE;

	@Setter
	@Getter 
	private boolean selected = false;

    /**
     * C'tor of CellRenderer
     * 
     * @param distance
     *            distance on the HexagonBoard
     * @param angle
     *            angle on the HexagonBoard
     * @param ingeniousColor
     *            Color to be rendered
     */
    public CellRenderer(final int distance, final int angle,
            final IngeniousColor ingeniousColor) {
        super();
        this.distance = distance;
        this.angle = angle;
        this.ingeniousColor = ingeniousColor;
        this.setSize(DIAMETER, DIAMETER);
        this.setPreferredSize(new Dimension(DIAMETER, DIAMETER));
        this.setOpaque(false);
    }

    /**
     * paint Cell
     * 
     * @param g
     *            graphic context
     */
    @Override
    public void paintComponent(final Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        drawHexagon(g2d);
        if (ingeniousColor != IngeniousColor.WHITE) {
            paintColorName(g2d);
        } else {
            paintDistanceAndAngle(g2d);
        }
    }

    /**
     * paint distance and angle on the hexagon cell
     * 
     * @param g2d
     *            graphical context to be painted on
     */
    private void paintDistanceAndAngle(final Graphics2D g2d) {
        String distanceAndAngle = this.getDistance() + "/" + this.getAngle();
        paintString(g2d, distanceAndAngle);
    }

    /**
     * paint the first char of the color on cell
     * 
     * @param g2d
     *            graphic context
     */
    private void paintColorName(final Graphics2D g2d) {
        String firstCharOfColor = ingeniousColor.name().substring(0, 1);
        paintString(g2d, firstCharOfColor);
    }

    /**
     * @param g2d graphical context
     * @param str string to be painted
     */
    private void paintString(final Graphics2D g2d, final String str) {
        g2d.setColor(Color.BLACK);
        int stringWidth = g2d.getFontMetrics().stringWidth(str);
        int stringAscent = g2d.getFontMetrics().getAscent();
        g2d.drawString(str, DIAMETER / 2 - stringWidth / 2,
                DIAMETER / 2 + stringAscent / 2);
    }

    /**
     * @param g2d
     *            graphic context
     */
    private void drawHexagon(final Graphics2D g2d) {
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        Shape path = calculateHexagonOutlinePath();
        g2d.setColor(this.ingeniousColor.getColor());
		//set thicker outline if the cell was selected
		if( this.isSelected() ){
			g2d.setStroke(new BasicStroke(3));
		}else {
			g2d.setStroke(new BasicStroke(1));
		}
        g2d.fill(path);
        g2d.setColor(Color.BLACK);
        g2d.draw(path);
    }

    /**
     * calculate a hexagon's outline NOTE: this peace of code is borrowed from
     * "hardwired" in
     * http://www.java-forums.org/java-2d/17082-developing-hex-board
     * -strategy-game.html
     * 
     * @return outline path
     */
    private Shape calculateHexagonOutlinePath() {
        Path2D.Double path = new Path2D.Double();
        double thetaInc = 2 * Math.PI / SIDES;
        double theta = thetaInc;
        double tmpX = RADIUS * Math.cos(theta);
        double tmpY = RADIUS * Math.sin(theta);
        path.moveTo(tmpX, tmpY);
        for (int i = 0; i < SIDES; i++) {
            theta += thetaInc;
            tmpX = RADIUS * Math.cos(theta);
            tmpY = RADIUS * Math.sin(theta);
            path.lineTo(tmpX, tmpY);
        }
        AffineTransform at = AffineTransform.getTranslateInstance(RADIUS,
                RADIUS);
        return at.createTransformedShape(path);
    }

}
